package com.woniuxy.merchant.config;

import cn.hutool.json.JSONUtil;
import com.woniu.commons.util.RedisKey;
import com.woniu.commons.util.WebUtil;
import com.woniu.zsd.commons.core.exception.ZsdException;
import com.woniu.zsd.commons.core.model.Result;
import com.woniu.zsd.merchant.client.PermissionClient;
import com.woniu.zsd.merchant.client.UserClient;
import com.woniu.zsd.merchant.form.Permission;
import com.woniu.zsd.merchant.form.UserInfo;
import com.woniuxy.merchant.entity.ChatMessage;
import com.woniuxy.merchant.mapper.ChatMessageMapper;
import com.woniuxy.merchant.service.IChatMessageService;
import com.woniuxy.merchant.util.MerchartTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class MessageHandler extends AbstractWebSocketHandler {
	@Resource
	private StringRedisTemplate stringRedisTemplate;

	private ConcurrentHashMap<String, WebSocketSession> sessions = new ConcurrentHashMap<>();

	@Autowired
    private MerchartTokenUtil tokenUtil;

	@Autowired
	private UserClient userClient;

	@Autowired
	private PermissionClient permissionClient;
	@Resource
	private IChatMessageService chatMessageService;
	@Resource
	private ChatMessageMapper chatMessageMapper;

	/**
	 * ps：连接关闭执行该方法
	 */
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		//session就是中断的连接对象
		System.out.println("连接关闭，关闭原因:"+status.getReason());
	}
	/**
	 * ps：连接异常中断执行该方法
	 */
	@Override
	public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
		//session就是中断的连接对象
		String id = session.getAttributes().get("id").toString();
		sessions.remove(id);
		System.out.println("连接异常中断,中断原因:"+exception.getMessage());
	}
	/**
	 * ps：当客户端与服务器成功建立连接会执行该方法
	 */
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		String token = session.getUri().getQuery().split("=")[1];
		System.out.println(token);
		String adminId = null;
		String userId = null;
		if (stringRedisTemplate.hasKey(RedisKey.USER_REFRESH_TOKEN_KEY(token))){
			userId = tokenUtil.getUserId(token).toString();
			sessions.put(userId, session);
			System.out.println("连接成功,连接对象为用户:" + session);
		} else {
			adminId = tokenUtil.getAdminId(token).toString();
			sessions.put(adminId, session);
			System.out.println("连接成功,连接对象为管理员:" + session);
		}
	}
	/**
	 * ps:服务器收到客户端消息时会执行该方法
	 */
	@Override
	public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
		System.out.println("服务器收到客户端消息,消息内容:" + message.getPayload());
		String messageInfo = message.getPayload().toString();

		// 将消息内容转换成 ChatMessage 对象
		ChatMessage chatMessage = JSONUtil.toBean(JSONUtil.parseObj(messageInfo), ChatMessage.class);

		Date date = new Date();
		String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
		chatMessage.setTimestamp(time);
		chatMessage.setIsRead(0);
		//从消息中取出token
		String token = JSONUtil.parseObj(messageInfo).getStr("token");
		String adminId = null;
		String userId = null;
		//判断token是管理员还是用户
		if (stringRedisTemplate.hasKey(RedisKey.USER_REFRESH_TOKEN_KEY(token))){
			//根据token获取用户id
			userId = tokenUtil.getUserId(token).toString();
			chatMessage.setSenderId(Integer.parseInt(userId));
			chatMessage.setSenderName(userClient.userInfo(token).getData().getNickName());
			chatMessage.setSenderAvatar(userClient.userInfo(token).getData().getHeadImg());
			// 初始化一个集合存放用户 ID（后续用于查数据库）
			Set<Integer> userIds = new HashSet<>();
			userIds.add(Integer.parseInt(userId));
		}else {
			// 管理员身份，根据 token 获取管理员 ID
			adminId = tokenUtil.getAdminId(token).toString();
			chatMessage.setSenderId(Integer.parseInt(adminId));
			chatMessage.setSenderName(permissionClient.selInfoByToken(token).getData().getName());
			chatMessage.setSenderAvatar(permissionClient.selInfoByToken(token).getData().getHeadImg());
			// 初始化一个集合存放用户 ID（后续用于查数据库）
			Set<Integer> adminIds =  new HashSet<>();
			adminIds.add(Integer.parseInt(adminId));

		}
		// 获取消息接收方 ID
		String receiverId = JSONUtil.parseObj(messageInfo).getStr("receiverId");
		// 用户首次发起聊天没有指定客服，则为其随机分配一个客服
		if (userId != null && (receiverId == null || receiverId.isEmpty())){
			//判断是否存在客服记录
			if (stringRedisTemplate.hasKey(RedisKey.TALK_FORM_USER_KEY(userId))){
				//获取第一位客服
				receiverId = stringRedisTemplate.opsForZSet().range(RedisKey.TALK_FORM_USER_KEY(userId), 0, 0).iterator().next();
				System.out.println("之前客服id:"+receiverId);
			}else{
				// 如果没有历史客服记录，则随机分配一个客服
				Integer customerServiceId = permissionClient.getCustomerService(Integer.valueOf(userId)).getData();

				System.out.println("随机客服id:"+customerServiceId);
				receiverId = customerServiceId.toString();
				//如果客服不在线，则返回错误信息
				if (receiverId.equals(String.valueOf(0))) {
					throw new ZsdException("当前没有客服在线", 500);
				}
			}
		}
		// 如果当前登录身份为管理员，校验其是否是客服身份（role 为 4）
		if (adminId != null){
			Set<Integer> adminIds = new HashSet<>();
			adminIds.add(Integer.parseInt(adminId));
			//通过管理员ID获取管理员信息
			Result<Permission> token1 = permissionClient.selInfoByToken(WebUtil.getRequest().getHeader("token"));

			if (token1.getData().getRoleId() != 4){
				throw new ZsdException("当前登录用户不是客服，请勿进行非法操作", 500);
			}
			// 对 userId 和 adminId 做最终绑定：如果发信人是用户，接收方就是客服；反之亦然
			if (userId != null){
				chatMessage.setReceiverId(Integer.parseInt(userId));
				chatMessage.setReceiverName(userClient.userInfo(token).getData().getNickName());
			}else{
				chatMessage.setReceiverId(Integer.parseInt(adminId));
				chatMessage.setReceiverName(permissionClient.selInfoByToken(token).getData().getName());
			}
			// 从 session 映射中查找接收方的 WebSocket 会话
			WebSocketSession receiverSession = sessions.get(receiverId);
			//如果接收方在线，则发送消息给接收方
			if (receiverSession != null && receiverSession.isOpen()){
				receiverSession.sendMessage(new TextMessage(JSONUtil.toJsonStr(chatMessage)));
			}else {
				//如果接收方不在线，则存储未读消息
				System.out.println("发送给离线用户");

			}
			// 在 Redis 中维护当前聊天联系人记录
			// 一个记录：用户对应的客服列表
			String formUserKey  = RedisKey.TALK_FORM_USER_KEY(userId);
			// 一个记录：客服对应的用户列表
			String formAdminKey = RedisKey.TALK_FORM_ADMIN_KEY(adminId);
			// 将聊天关系写入 Redis 的有序集合，score 为当前时间戳
			stringRedisTemplate.opsForZSet().add(formUserKey, adminId, date.getTime());
			stringRedisTemplate.opsForZSet().add(formAdminKey, userId, date.getTime());
			// 聊天记录存储（双向）
			// 一个用于管理员查聊天记录
			String adminUserKey = RedisKey.TALK_ADMIN_USER_KEY(userId, adminId);
			// 一个用于用户查聊天记录
			String userAdminKey = RedisKey.TALK_USER_ADMIN_KEY(userId, adminId);
			// 将消息 JSON 存入 Redis 的聊天记录中（双向各存一份）
			stringRedisTemplate.opsForZSet().add(adminUserKey, JSONUtil.parseObj(chatMessage).toString(), date.getTime());
			stringRedisTemplate.opsForZSet().add(userAdminKey, JSONUtil.parseObj(chatMessage).toString(), date.getTime());

			chatMessageMapper.insert(chatMessage);
		}

	}

	@Override
	public boolean supportsPartialMessages() {
		// TODO Auto-generated method stub
		return false;
	}


}